/*
 * Copyright 2009 Eat Local Food, LLC
 * Copyright (c) 2007 osCommerce (this file was written after
 * code review of osCommerce).
 *
 * This file is part of gwtCommerce.
 *
 * gwtCommerce is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * gwtCommerce is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with gwtCommerce.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.elf.gwt.store.client.subcomponents;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.elf.gwt.common.client.access.RequestParameter;
import com.elf.gwt.common.client.callback.SubComponentCallback;
import com.elf.gwt.common.client.model.AccountMetaModel;
import com.elf.gwt.common.client.model.AccountModel;
import com.elf.gwt.common.client.model.AddressModel;
import com.elf.gwt.common.client.model.CountryModel;
import com.elf.gwt.common.client.model.ZoneModel;
import com.elf.gwt.common.client.subcomponent.CommonSubComponent;
import com.elf.gwt.common.client.utils.CommonUtils;
import com.elf.gwt.store.client.GWTCommerceConstants;
import com.elf.gwt.store.client.StoreComponentController;
import com.elf.gwt.store.client.components.AccountComponent;
import com.elf.gwt.store.client.components.CheckoutComponent;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.InlineHTML;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;

/**
 *  Subcomponent for Shipping and Billing Address.
 */
public class CheckoutAddressSubComponent extends CheckoutSubComponent
{
	protected AddressModel addressModel;
	protected InlineHTML warningLabel;

	protected InlineLabel nameLabel;
	protected InlineLabel companyLabel;
	protected InlineHTML addressLabel;
	protected Grid grid;
	protected TextBox nameBox;
	protected TextBox companyBox;
	protected ListBox countryListBox;
	protected TextBox streetBox;
	protected TextBox suburbBox;
	protected TextBox postCodeBox;
	protected TextBox cityBox;
	protected ListBox stateListBox;
	protected DialogBox addressDialogBox;

	protected List<CountryModel> countryModels;

	protected boolean asAppearsOnCC = false;
	protected boolean checkoutCompleted;

	/**
	 * Constructor
	 */
	public CheckoutAddressSubComponent(
			StoreComponentController controller, 
			SubComponentCallback callback)
	{
		super(controller, null, callback);
		this.addressModel = new AddressModel();

		nameBox = new TextBox();
		companyBox = new TextBox(); 
		countryListBox = new ListBox();
		streetBox = new TextBox(); 
		suburbBox = new TextBox();
		postCodeBox = new TextBox(); 
		cityBox = new TextBox(); 
		stateListBox = new ListBox();

		nameLabel = new InlineLabel();
		companyLabel = new InlineLabel();
		addressLabel = new InlineHTML();
	}

	/**
	 * build
	 */
	public void build() 
	{
		if (accountComponent == null) accountComponent = (AccountComponent)controller.getComponent("AccountComponent");
		AccountModel accountModel = accountComponent.getAccountModel();
		AccountMetaModel accountMetaModel = accountComponent.getAccountMetaModel();

		GWTCommerceConstants constants = getController().getStoreConstants();
		countryModels = accountMetaModel.getCountryModels();
		thisComponent.clear();

		if (accountModel.getId() > 0)
		{
			int gridRow= 2;
			if (accountMetaModel.isDisplayCompany()) gridRow++;
			if (!checkoutCompleted) gridRow++;
			grid = new Grid(gridRow,3);

			grid.setStyleName(handle + "SubPanel");
			grid.getColumnFormatter().setStyleName(0, handle + "SubPanelCol0");
			CellFormatter cf = grid.getCellFormatter();
			cf.setWordWrap(0, 1, false);
			cf.setWordWrap(1, 1, false);
			gridRow = 0;
			if (accountMetaModel.isDisplayCompany())
			{
				cf.setWordWrap(2, 1, false);
				CommonUtils.addGridWidget(handle, gridRow, companyLabel, grid, "", "", "");
				gridRow++;
			}

			CommonUtils.addGridWidget(handle, gridRow, nameLabel, grid, "", "", "");

			gridRow++;
			CommonUtils.addGridWidget(handle, gridRow, addressLabel, grid, "", "", "");
			gridRow++;
			thisComponent.add(grid);

			if (!checkoutCompleted)
			{
				Button addressBookButton = new Button(controller.getStoreConstants().CheckoutComponentAddressBook(),
						new ClickHandler() {
					public void onClick(ClickEvent event) {
						DialogBox dialogBox = getAddressDialogBox();
						dialogBox.center();
						dialogBox.show();
					}}
				);
				grid.setWidget(gridRow, 1, addressBookButton);
			}
		}
		else
		{
			int gridrow = 0;
			gridrow++;
			if (accountMetaModel.isDisplayCompany()) gridrow++;
			gridrow++;
			countryListBox.addChangeHandler(new ChangeHandler() {
				public void onChange(ChangeEvent event) {
					if (accountComponent.getAccountMetaModel().isDisplayState())
					{
						CountryModel cmodel = countryModels.get(countryListBox.getSelectedIndex());
						String countryName = cmodel.getName();
						CommonUtils.updateStateListBox(countryName, null, countryModels, stateListBox);
					}
				}
			});

			gridrow++;
			if (accountMetaModel.isDisplaySuburb()) gridrow++;
			gridrow++;
			gridrow++;
			if (accountMetaModel.isDisplayState())gridrow++;

			if (accountModel.getId() > 0) gridrow++;

			grid = new Grid(gridrow,3);

			gridrow = 0;
			grid.setStyleName(handle + "SubPanel");
			grid.getColumnFormatter().setStyleName(0, handle + "SubPanelCol0");

			if (accountMetaModel.isDisplayCompany())
			{ 
				CommonUtils.addGridWidget(handle,gridrow, companyBox, grid, "Company", 
						constants.AccountComponentCompany(), constants.AccountComponentCompanyText());
				gridrow++;
			}

			CommonUtils.addGridWidget(handle, gridrow, nameBox, grid, "Name", 
					"Name:", "*");
			gridrow++;

			CommonUtils.addGridWidget(handle, gridrow, countryListBox, grid, "Country", 
					constants.AccountComponentCountry(), constants.AccountComponentCountryText());
			gridrow++;

			CommonUtils.addGridWidget(handle, gridrow, streetBox, grid, "StreetAddress", 
					constants.AccountComponentStreetAddress(), constants.AccountComponentStreetAddressText());
			gridrow++;

			if (accountMetaModel.isDisplaySuburb())
			{
				suburbBox = new TextBox(); 
				CommonUtils.addGridWidget(handle, gridrow, suburbBox, grid, "Suburb", 
						constants.AccountComponentSuburb(), constants.AccountComponentSuburbText());
				gridrow++;
			}

			CommonUtils.addGridWidget(handle, gridrow, postCodeBox, grid, "PostCode", 
					constants.AccountComponentPostCode(), constants.AccountComponentPostCodeText());
			gridrow++;


			CommonUtils.addGridWidget(handle, gridrow, cityBox, grid, "City", 
					constants.AccountComponentCity(), constants.AccountComponentCityText());
			gridrow++;

			if (accountMetaModel.isDisplayState())
			{
				CommonUtils.addGridWidget(handle, gridrow, stateListBox, grid, "State", 
						constants.AccountComponentState(), constants.AccountComponentStateText());
				gridrow++;
			}
			thisComponent.add(grid);
		}
		thisComponent.add(new InlineHTML("<br/>"));
		update(addressModel, false);
	}

	/**
	 * 
	 * @param amodel
	 * @return
	 */
	protected DialogBox getAddressDialogBox() {
		addressDialogBox = new DialogBox();
		addressDialogBox.setWidth("500px");
		addressDialogBox.setText(getController().getStoreConstants().CheckoutComponentAddressBook());

		AccountAddressSubComponent accountAddressSubComponent = new AccountAddressSubComponent(
				getController(), 
				addressSubComponentCallback, 
				CheckoutComponent.Checkout);

		addressDialogBox.setWidget(accountAddressSubComponent);
		addressDialogBox.setStyleName("AccountComponentDialogBox");
		// Return the dialog box
		return addressDialogBox;
	}

	protected SubComponentCallback addressSubComponentCallback = 
		new SubComponentCallback() {

		public void onNavigate(CommonSubComponent subComponent) {
			addressDialogBox.hide();
		}

		public void onSuccess(CommonSubComponent subComponent) {
			AccountModel accountModel = accountComponent.getAccountModel();
			update(accountModel.getEditAddress());
			accountModel.setEditAddress(null);
			addressDialogBox.hide();
			callback.onSuccess(thisComponent);
		}

		public void onError(CommonSubComponent subComponent, Throwable exception) {}
	};

	protected void update(AddressModel addressModel)
	{
		update(addressModel, true);
	}

	protected void update(AddressModel addressModel, boolean updateName)
	{
		AccountModel accountModel = accountComponent.getAccountModel();
		AccountMetaModel accountMetaModel = accountComponent.getAccountMetaModel();
		this.addressModel.update(addressModel);

		if (accountModel.getId() > 0)
		{
			if (updateName || (nameLabel.getText() == null || nameLabel.getText().length() == 0))
			{
				nameBox.setText(addressModel.getFirstname() + " " + addressModel.getLastname());
				nameLabel.setText(addressModel.getFirstname() + " " + addressModel.getLastname());
			}
			if (accountMetaModel.isDisplayCompany()) companyLabel.setText(addressModel.getCompany());

			StringBuffer strAddressLabel = new StringBuffer();
			strAddressLabel.append("<span>");
			strAddressLabel.append(addressModel.getStreet() + "<br/>");
			if (accountMetaModel.isDisplaySuburb()) strAddressLabel.append(addressModel.getSuburb() + "<br/>");
			strAddressLabel.append(addressModel.getPostcode() + "<br/>");
			strAddressLabel.append(addressModel.getCity());

			if (accountMetaModel.isDisplayState())
			{
				strAddressLabel.append(", " + addressModel.getState());
			}
			strAddressLabel.append("<br/>" + addressModel.getCountry());
			strAddressLabel.append("</span>");
			addressLabel.setHTML(strAddressLabel.toString());
		}
		else if (addressModel != null)
		{
			if (updateName || (nameLabel.getText() == null || nameLabel.getText().length() == 0))
			{
				nameBox.setText(addressModel.getFirstname() + " " + addressModel.getLastname());
			}
			if (accountMetaModel.isDisplayCompany()) companyBox.setText(addressModel.getCompany());
			streetBox.setText(addressModel.getStreet());
			if (accountMetaModel.isDisplaySuburb()) suburbBox.setText(addressModel.getSuburb());
			postCodeBox.setText(addressModel.getPostcode());
			cityBox.setText(addressModel.getCity());

			Iterator<CountryModel> iter = countryModels.iterator();
			int i = 0;
			while(iter.hasNext())
			{
				CountryModel cmodel = iter.next();
				countryListBox.addItem(cmodel.getName(),cmodel.getName());
				if (cmodel.getName().equals(addressModel.getCountry()))
				{
					countryListBox.setItemSelected(i, true);
				}
				else
				{
					countryListBox.setItemSelected(i, false);
				}
				i++;
			}
			if (accountMetaModel.isDisplayState())
			{
				CommonUtils.updateStateListBox(addressModel.getCountry(), addressModel.getState(), countryModels, stateListBox);
			}
		}
	}

	public void nameWarning(boolean asAppearsOnCC)
	{
		AccountModel accountModel = accountComponent.getAccountModel();
		AccountMetaModel accountMetaModel = accountComponent.getAccountMetaModel();
		this.asAppearsOnCC = asAppearsOnCC;
		int gridRow = 0;
		if (accountMetaModel.isDisplayCompany()) gridRow++;

		if (asAppearsOnCC && !checkoutCompleted)
		{
			grid.setWidget(gridRow, 1, nameBox);
			grid.setText(gridRow, 2, getController().getStoreConstants().CheckoutComponentNameWarning());
		}
		else
		{
			if (accountModel.getId() > 0)
			{
				nameLabel.setText(nameBox.getText());
				grid.setWidget(gridRow, 1, nameLabel);
				grid.setText(gridRow, 2, "");
			}
			else
			{
				grid.setWidget(gridRow, 1, nameBox);
				grid.setText(gridRow, 2, getController().getStoreConstants().CheckoutComponentNameNoWarning());
			}
		}

	}

	public AddressModel getAddressModel()
	{
		try {
			AccountModel accountModel = accountComponent.getAccountModel();
			AccountMetaModel accountMetaModel = accountComponent.getAccountMetaModel();
			if (asAppearsOnCC)
				addressModel.setName(nameBox.getText());
			else
			{
				if (accountModel.getId() > 0)
					addressModel.setName(nameLabel.getText());
				else
					addressModel.setName(nameBox.getText());
			}

			if (accountModel.getId() < 1)
			{
				if (accountMetaModel.isDisplayCompany()) addressModel.setCompany(companyBox.getText());
				addressModel.setStreet(streetBox.getText());
				if (accountMetaModel.isDisplaySuburb()) addressModel.setSuburb(suburbBox.getText());
				addressModel.setPostcode(postCodeBox.getText());
				addressModel.setCity(cityBox.getText());

				if (countryListBox != null) {
					CountryModel cmodel = countryModels.get(countryListBox.getSelectedIndex());
					String countryName = cmodel.getName();
					addressModel.setCountry(countryName);

					if (accountMetaModel.isDisplayState())
					{
						ZoneModel zmodel = cmodel.getZones().get(stateListBox.getSelectedIndex());
						addressModel.setState(zmodel.getCode());
					}
				}
			}
		}
		catch (Exception e) {
			GWT.log("CheckoutAddressSubComponent.getModel() Exception", e);
		}
		return addressModel;
	}

	public void setAddressModel(AddressModel addressModel) {
		this.addressModel.update(addressModel);
	}

	public List<RequestParameter> getAdditionalRequestParameters()
	{
		GWT.log("CheckoutAddressSubComponent.getAdditionalRequestParameters start");
		AccountMetaModel accountMetaModel = accountComponent.getAccountMetaModel();

		List<RequestParameter> requestParameters = new ArrayList<RequestParameter>();
		AddressModel addressModel = getAddressModel();
		if (addressModel != null) {

			requestParameters.add(new RequestParameter("Name", addressModel.getName()));

			if (addressModel.getId() > 0)
			{
				requestParameters.add(new RequestParameter("AddressId", addressModel.getId()));
			}
			else
			{
				if (accountMetaModel.isDisplayCompany()) 
					requestParameters.add(new RequestParameter("Company", addressModel.getCompany()));

				requestParameters.add(new RequestParameter("Street", addressModel.getStreet()));

				if (accountMetaModel.isDisplaySuburb()) 
					requestParameters.add(new RequestParameter("Suburb", addressModel.getSuburb()));

				requestParameters.add(new RequestParameter("Postcode", addressModel.getPostcode()));
				requestParameters.add(new RequestParameter("City", addressModel.getCity()));
				requestParameters.add(new RequestParameter("Country", addressModel.getCountry()));

				if (accountMetaModel.isDisplayState())
					requestParameters.add(new RequestParameter("State", addressModel.getState()));
			}
		}

		GWT.log("CheckoutAddressSubComponent.getAdditionalRequestParameters end");
		return requestParameters;
	}

	public String validate(String action)
	{
		return "";
	}

	public boolean isCheckoutCompleted() {
		return checkoutCompleted;
	}

	public void setCheckoutCompleted(boolean checkoutCompleted) {
		this.checkoutCompleted = checkoutCompleted;
	}

}
